#!/usr/bin/python3

# Copyright (c) 2020-2021 Fpemud <fpemud@sina.com>
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE.


import enum
from .util import OrderedEnum


class MachineType(OrderedEnum):

    # these are a subset of CHASSIS value range in /etc/machine-info

    DESKTOP     = "desktop"
    LAPTOP      = "laptop"
    TABLET      = "tablet"
    CONVERTIBLE = "convertible"
    HANDSET     = "handset"
    WATCH       = "watch"
    SERVER      = "server"
    VM          = "vm"
    CONTAINER   = "container"


class ComponentType(OrderedEnum):

    CPU = "cpu"

    MEMORY = "memory"

    MOTHER_BOARD = "mother_board"

    GRAPHICS_CARD = "graphics_card"
    SOUND_CARD = "sound_card"
    COMPUTING_CARD = "computing_card"

    HARDDISK = "harddisk"
    HARDDISK_BRACKET = "harddisk_bracket"

    BLUETOOTH_DONGLE = "bluetooth_dongle"

    POWER = "power"

    CPU_FAN = "cpu_fan"
    CHASSIS_FAN = "chassis_fan"

    PUMP = "pump"

    MONITOR = "monitor"

    WEBCAM = "webcam"

    KEYBOARD = "keyboard"
    INTEGRATED_KEYBOARD = "integrated_keyboard"

    MOUSE = "mouse"
    INTEGRATED_MOUSE = "integrated_mouse"

    TRACKBALL = "trackball"
    FLIGHT_STICK = "flight_stick"
    STEERING_WHEEL = "steering_wheel"
    GAMEPAD = "gamepad"

    LOUDSPEAKER = "loudspeaker"
    HEADSET = "headset"
    MICROPHONE = "microphone"

    USB_HUB = "usb_hub"
    PRINTER = "printer"

    TABLE = "table"

    PULSE_OXIMETER = "pulse_oximeter"


class DeviceType(OrderedEnum):

    PANEL_COVER = "panel_cover"

    POWER_SWITCH = "power_switch"
    POWER_BUTTON = "power_button"
    RESET_SWITCH = "reset_switch"
    RESET_BUTTON = "reset_button"

    CPU_CORE = "cpu_core"

    KEYBOARD = "keyboard"

    CAMERA = "camera"
    TREE_DIMENSION_SENSOR = "3d_sensor"

    LOUDSPEAKER = "loudspeaker"
    MICROPHONE = "microphone"

    RENDER_CHIP = "render_chip"
    SOUND_CHIP = "sound_chip"
    NETWORK_CONTROLLER = "network_controller"
    WIFI_CHIP = "wifi_chip"
    USB_HOST_CONTROLLER_2_0 = "usb_host_controller_2_0"
    USB_HOST_CONTROLLER_3_0 = "usb_host_controller_3_0"
    USB_HOST_CONTROLLER_3_1 = "usb_host_controller_3_1"
    BLUETOOTH_HOST_CONTROLLER = "bluetooth_host_controller"

    SCREEN = "screen"

    POINTER = "pointer"
    BATTERY = "battery"

    HWMON = "hwmon"
    SENSOR_TEMPERATURE = "sensor_temperature"
    LIGHT_SENSOR = "light_sensor"

    INPUT = "input"

    RFKILL = "rfkill"

    FAN = "fan"


class ConnectorType(OrderedEnum):

    MALE_CONNECTOR_CPU   = "male_connector_cpu"
    FEMALE_CONNECTOR_CPU = "female_connector_cpu"

    MALE_CONNECTOR_DDR    = "male_connector_ddr"
    MALE_CONNECTOR_DDR2   = "male_connector_ddr2"
    MALE_CONNECTOR_DDR3   = "male_connector_ddr3"
    MALE_CONNECTOR_DDR4   = "male_connector_ddr4"
    FEMALE_CONNECTOR_DDR  = "female_connector_ddr"
    FEMALE_CONNECTOR_DDR2 = "female_connector_ddr2"
    FEMALE_CONNECTOR_DDR3 = "female_connector_ddr3"
    FEMALE_CONNECTOR_DDR4 = "female_connector_ddr4"

    MALE_CONNECTOR_POWER_SWITH   = "male_connector_power_switch"
    MALE_CONNECTOR_RESET_SWITH   = "male_connector_reset_switch"
    FEMALE_CONNECTOR_POWER_SWITH = "female_connector_power_switch"                  # we define needle as female connector for power switch
    FEMALE_CONNECTOR_RESET_SWITH = "female_connector_reset_switch"                  # we define needle as female connector for reset switch

    MALE_CONNECTOR_TRS_3_5_AUDIO        = "male_connector_trs_3_5_audio"
    MALE_CONNECTOR_TRS_3_5_MICROPHONE   = "male_connector_trs_3_5_microphone"
    MALE_CONNECTOR_TRS_3_5_COMBO        = "male_connector_trs_3_5_combo"
    FEMALE_CONNECTOR_TRS_3_5_AUDIO      = "female_connector_trs_3_5_audio"          # 3.5mm audio jack
    FEMALE_CONNECTOR_TRS_3_5_MICROPHONE = "female_connector_trs_3_5_microphone"
    FEMALE_CONNECTOR_TRS_3_5_COMBO      = "female_connector_trs_3_5_combo"

    MALE_CONNECTOR_PCI_2   = "male_connector_pci_2"
    MALE_CONNECTOR_PCI_3   = "male_connector_pci_3"
    MALE_CONNECTOR_PCI_4   = "male_connector_pci_4"
    FEMALE_CONNECTOR_PCI_2 = "female_connector_pci_2"
    FEMALE_CONNECTOR_PCI_3 = "female_connector_pci_3"
    FEMALE_CONNECTOR_PCI_4 = "female_connector_pci_4"

    MALE_CONNECTOR_SATA_3   = "male_connector_sata_3"
    FEMALE_CONNECTOR_SATA_3 = "female_connector_sata_3"

    MALE_CONNECTOR_USB_2_0   = "male_connector_usb_2_0"
    MALE_CONNECTOR_USB_3_0   = "male_connector_usb_3_0"
    MALE_CONNECTOR_USB_C     = "male_connector_usb_c"
    FEMALE_CONNECTOR_USB_2_0 = "female_connector_usb_2_0"          # we can have male_connector, female_connector and combo_connector
    FEMALE_CONNECTOR_USB_3_0 = "female_connector_usb_3_0"          # we think there's no standalone cable, cable must be part of a component, so that we can only focus on connector
    FEMALE_CONNECTOR_USB_C   = "female_connector_usb_c"

    MALE_CONNECTOR_HDMI_2_0   = "male_connector_hdmi_2_0"
    FEMALE_CONNECTOR_HDMI_2_0 = "female_connector_hdmi_2_0"

    MALE_CONNECTOR_DP_1_4   = "male_connector_dp_1_4"
    MALE_CONNECTOR_DP_2_0   = "male_connector_dp_2_0"
    FEMALE_CONNECTOR_DP_1_4 = "female_connector_dp_1_4"
    FEMALE_CONNECTOR_DP_2_0 = "female_connector_dp_2_0"

    MALE_CONNECTOR_BLUETOOTH_2_0   = "male_connector_bluetooth_2_0"
    MALE_CONNECTOR_BLUETOOTH_4_2   = "male_connector_bluetooth_4_2"
    MALE_CONNECTOR_BLUETOOTH_5_0   = "male_connector_bluetooth_5_0"
    FEMALE_CONNECTOR_BLUETOOTH_2_0 = "female_connector_bluetooth_2_0"
    FEMALE_CONNECTOR_BLUETOOTH_4_2 = "female_connector_bluetooth_4_2"
    FEMALE_CONNECTOR_BLUETOOTH_5_0 = "female_connector_bluetooth_5_0"

    ETHERNET_PORT_TE  = "ethernet_port_te"          # 10M ethernet
    ETHERNET_PORT_FE  = "ethernet_port_fe"          # 100M ethernet
    ETHERNET_PORT_GE  = "ethernet_port_ge"          # 1000M ethernet
    ETHERNET_PORT_TGE = "ethernet_port_tge"         # 10000M ethernet
    ETHERNET_PORT_FGE = "ethernet_port_fge"         # 40000M ethernet
    ETHERNET_PORT_HGE = "ethernet_port_hge"         # 100000M ethernet

    WIFI_ATTENNA = "wifi_attenna"                   # not very sure

    MALE_CONNECTOR_FAN_CPU   = "male_connector_fan_cpu"
    FEMALE_CONNECTOR_FAN_CPU = "female_connector_fan_cpu"

    def is_male_connector(self):
        if self.value.startswith("male_connector_"):
            return True
        return False

    def is_female_connector(self):
        if self.value.startswith("female_connector_"):
            return True
        return False

    def is_combo_connector(self):
        return False

    @staticmethod
    def are_connectors_compatible(connector1, connector2, strict=False):
        if connector1.value.startswith("male_connector_") and connector2.value.startswith("female_connector_"):
            pass
        elif connector1.value.startswith("female_connector_") and connector2.value.startswith("male_connector_"):
            pass
        else:
            return False

        assert False


class OfflineReason(enum.Enum):
    DISABLED_BY_HARDWARE = "disabled_by_hardware"
    DISABLED_BY_BIOS = "disabled_by_bios"
    DISABLED_BY_KERNEL_CONFIG = "disabled_by_kernel_config"
    DISABLED_BY_KERNEL_CMDLINE_PARAMETER = "disabled_by_kernel_cmdline_parameter"
    DISABLED_BY_USERSPACE_CONFIG = "disabled_by_userspace_config"
    SUSPENDED_BY_HARDWARE = "suspended_by_hardware"
    SUSPENDED_BY_BIOS = "suspended_by_bios"
    SUSPENDED_BY_USERSPACE_CONFIG = "suspended_by_userspace_config"
    REMOVED = "removed"
    POWER_OFF = "power_off"
    UNKNOWN = "unknown"

    def is_disabled(self):
        return self in [
            OfflineReason.DISABLED_BY_HARDWARE,
            OfflineReason.DISABLED_BY_BIOS,
            OfflineReason.DISABLED_BY_KERNEL_CONFIG,
            OfflineReason.DISABLED_BY_KERNEL_CMDLINE_PARAMETER,
            OfflineReason.DISABLED_BY_USERSPACE_CONFIG
        ]

    def is_suspended(self):
        return self in [
            OfflineReason.SUSPENDED_BY_HARDWARE,
            OfflineReason.SUSPENDED_BY_BIOS,
            OfflineReason.SUSPENDED_BY_USERSPACE_CONFIG,
        ]
